package com.jeejio.common.rcv.decoration

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.ceil

/**
 * Author: JFangZ
 * Email: janezhang1901@163.com
 * Date: 2021/4/19 10:46
 * Description:The divider style decoration for grid layout manager.
 */
class GridDividerDecoration private constructor(builder: Builder) : RecyclerView.ItemDecoration() {
    companion object {
        const val LEFT = "left"
        const val TOP = "top"
        const val RIGHT = "right"
        const val BOTTOM = "bottom"
    }

    private var columnWidth = 0
    private var firstColumnLeftWidth = 0
    private var lastColumnRightWidth = 0
    private var rowWidth = 0

    /**
     * The width of the top of first row.
     */
    private var firstRowTopWidth = 0

    /**
     * The width of the bottom of last row.
     */
    private var lastRowBottomWidth = 0

    /**
     * Divider will add the padding of item or not.
     */
    private var offset = true

    private val outRect = Rect()
    private val paint = Paint()

    init {
        columnWidth = builder.columnWidth
        firstColumnLeftWidth = builder.firstColumnLeftWidth
        lastColumnRightWidth = builder.lastColumnRightWidth
        rowWidth = builder.rowWidth
        firstRowTopWidth = builder.firstRowTopWidth
        lastRowBottomWidth = builder.lastRowBottomWidth
        offset = builder.offset
        paint.isAntiAlias = true
        paint.color = builder.color
    }

    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
        if (!offset) {
            return
        }
        val layoutManager = parent.layoutManager as? GridLayoutManager ?: return
        val adapter = parent.adapter ?: return
        val position = parent.getChildAdapterPosition(view)
        val spanCount = (parent.layoutManager as GridLayoutManager?)!!.spanCount
        if (layoutManager.orientation == RecyclerView.VERTICAL) {
            // 父 RecyclerView 宽度
            val parentWidth = parent.measuredWidth
            // 每一个 item 平分的宽度
            val eachItemWidthWithPadding = parentWidth / spanCount
            // 计算分隔线占的总宽度
            val dividerTotalWidth = firstColumnLeftWidth + lastColumnRightWidth + columnWidth * (spanCount + 1 - 2)
            // 计算每一个 item 最终应该显示的宽度
            val eachItemWidth = (parentWidth - dividerTotalWidth) / spanCount
            // 计算每一个 item 的左右偏移量
            val offsetMapList: MutableList<Map<String, Int>> = ArrayList()
            var previousRight = 0
            for (i in 0 until spanCount) {
                val left: Int = if (i == 0) {
                    firstColumnLeftWidth
                } else {
                    columnWidth - previousRight
                }
                val right = eachItemWidthWithPadding - eachItemWidth - left
                previousRight = right
                val offsetMap: MutableMap<String, Int> = HashMap()
                offsetMap[LEFT] = left
                offsetMap[RIGHT] = right
                offsetMapList.add(offsetMap)
            }
            var top = 0
            if (isFirstRow(position, spanCount)) {
                top = firstRowTopWidth
            }
            var bottom = 0
            bottom = if (isLastRow(position, adapter.itemCount, spanCount)) {
                lastRowBottomWidth
            } else {
                rowWidth
            }
            outRect.set(offsetMapList[position % spanCount][LEFT]!!, top, offsetMapList[position % spanCount][RIGHT]!!, bottom)
        }
    }

    override fun onDrawOver(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        val layoutManager = (parent.layoutManager ?: return) as? LinearLayoutManager ?: return
        if ((layoutManager as GridLayoutManager).orientation == RecyclerView.VERTICAL) {
            drawVertical(c, parent, state)
        }
    }

    private fun drawVertical(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
        // 获取 RecyclerView 的 Item 数量
        val childCount = parent.childCount
        val adapter = parent.adapter ?: return
        val spanCount = (parent.layoutManager as GridLayoutManager?)!!.spanCount
        // 父 RecyclerView 宽度
        val parentWidth = parent.measuredWidth
        // 每一个 item 平分的宽度
        val eachItemWidthWithPadding = parentWidth / spanCount
        // 计算分隔线占的总宽度
        val dividerTotalWidth = firstColumnLeftWidth + lastColumnRightWidth + columnWidth * (spanCount + 1 - 2)
        // 计算每一个 item 最终应该显示的宽度
        val eachItemWidth = (parentWidth - dividerTotalWidth) / spanCount
        // 计算每一个 item 的左右分隔线的宽度
        val widthMapList: MutableList<Map<String, Int>> = ArrayList()
        var previousRight = 0
        for (i in 0 until spanCount) {
            var left: Int
            left = if (i == 0) {
                firstColumnLeftWidth
            } else {
                columnWidth - previousRight
            }
            val right = eachItemWidthWithPadding - eachItemWidth - left
            previousRight = right
            val offsetMap: MutableMap<String, Int> = HashMap()
            offsetMap[LEFT] = left
            offsetMap[RIGHT] = right
            widthMapList.add(offsetMap)
        }
        for (i in 0 until childCount) {
            val childView = parent.getChildAt(i)
            val position = parent.getChildAdapterPosition(childView)
            getItemOffsets(outRect, childView, parent, state)
            var top = 0
            if (isFirstRow(position, spanCount)) {
                top = firstRowTopWidth
            }
            var bottom = 0
            bottom = if (isLastRow(position, adapter.itemCount, spanCount)) {
                lastRowBottomWidth
            } else {
                rowWidth
            }
            // 左
            c.drawRect((childView.left - outRect.left
                    ).toFloat(), childView.top
                    .toFloat(), (childView.left - outRect.left + widthMapList[position % spanCount][LEFT]!!
                    ).toFloat(), childView.bottom
                    .toFloat(), paint)
            // 上
            c.drawRect((childView.left - widthMapList[position % spanCount][LEFT]!!
                    ).toFloat(), (childView.top - outRect.top
                    ).toFloat(), (childView.right + widthMapList[position % spanCount][RIGHT]!!
                    ).toFloat(), (childView.top - outRect.top + top
                    ).toFloat(), paint)
            // 右
            c.drawRect((childView.right + outRect.right - widthMapList[position % spanCount][RIGHT]!!
                    ).toFloat(), childView.top
                    .toFloat(), (childView.right + outRect.right
                    ).toFloat(), childView.bottom
                    .toFloat(), paint)
            //            // 下
            c.drawRect((childView.left - widthMapList[position % spanCount][LEFT]!!
                    ).toFloat(), (childView.bottom + outRect.bottom - bottom
                    ).toFloat(), (childView.right + widthMapList[position % spanCount][RIGHT]!!
                    ).toFloat(), (childView.bottom + outRect.bottom
                    ).toFloat(), paint)
        }
    }

    private fun isFirstRow(position: Int, spanCount: Int): Boolean {
        return position < spanCount
    }

    private fun isLastRow(position: Int, itemCount: Int, spanCount: Int): Boolean {
        val totalRow = ceil(itemCount.toDouble() / spanCount.toDouble()).toInt()
        return position >= (totalRow - 1) * spanCount
    }

    class Builder {
        internal var columnWidth = 0
        internal var firstColumnLeftWidth = 0
        internal var lastColumnRightWidth = 0
        internal var rowWidth = 0
        internal var firstRowTopWidth = 0
        internal var lastRowBottomWidth = 0
        internal var color = 0x00000000
        internal var offset = false

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width between column.It will also set firstColumnLeftWidth and
         * lastColumnRightWidth at the same time.
         */
        fun setColumnWidth(columnWidth: Int): Builder {
            this.columnWidth = columnWidth
            firstColumnLeftWidth = columnWidth
            lastColumnRightWidth = columnWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width of the left of first column.Please call it after setColumnWidth(),
         * otherwise call setColumnWidth() will override firstColumnLeftWidth.
         */
        fun setFirstColumnLeftWidth(firstColumnLeftWidth: Int): Builder {
            this.firstColumnLeftWidth = firstColumnLeftWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width of the right of last column.Please call it after setColumnWidth(),
         * otherwise call setColumnWidth() will override lastColumnRightWidth.
         */
        fun setLastColumnRightWidth(lastColumnRightWidth: Int): Builder {
            this.lastColumnRightWidth = lastColumnRightWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width between row.It will also set firstRowTopWidth and
         * lastRowBottomWidth at the same time.
         */
        fun setRowWidth(rowWidth: Int): Builder {
            this.rowWidth = rowWidth
            firstRowTopWidth = rowWidth
            lastRowBottomWidth = rowWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width of the top of first row.Please call it after setRowWidth(),
         * otherwise call setRowWidth() will override firstRowTopWidth.
         */
        fun setFirstRowTopWidth(firstRowTopWidth: Int): Builder {
            this.firstRowTopWidth = firstRowTopWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 11:01
         * Description:Set the width of the bottom of last row.Please call it after setLastRowBottomWidth(),
         * otherwise call setLastRowBottomWidth() will override lastRowBottomWidth.
         */
        fun setLastRowBottomWidth(lastRowBottomWidth: Int): Builder {
            this.lastRowBottomWidth = lastRowBottomWidth
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 15:30
         * Description:Set the color of divider.
         */
        fun setColor(color: Int): Builder {
            this.color = color
            return this
        }

        /**
         * Author: JFangZ
         * Email: janezhang1901@163.com
         * Date:2021/4/19 15:30
         * Description:Set the divider will add the padding of item or not.
         */
        fun setOffset(offset: Boolean): Builder {
            this.offset = offset
            return this
        }

        fun build(): GridDividerDecoration {
            return GridDividerDecoration(this)
        }
    }
}